#include "../iBe.h"
#include <stdio.h>

OSMesaRender::OSMesaRender():Render()
{}

OSMesaRender::~OSMesaRender()
{
  if (buffer)
    free(buffer);

  if (ctx)
    OSMesaDestroyContext(ctx);
}

void OSMesaRender::writePPM(const char* _filename)
{
  const int binary = 0;
  FILE *f = fopen( _filename, "w" );
  if (f) {
    int i, x, y;
    const GLubyte *ptr = (GLubyte*) buffer;
    if (binary) {
      fprintf(f,"P6\n");
      fprintf(f,"# ppm-file created by osdemo.c\n");
      fprintf(f,"%i %i\n", width,height);
      fprintf(f,"255\n");
      fclose(f);
      f = fopen( _filename, "ab" );  /* reopen in binary append mode */
      for (y=height-1; y>=0; y--) {
	for (x=0; x<width; x++) {
	  i = (y*width + x) * 4;
	  fputc(ptr[i], f);   /* write red */
	  fputc(ptr[i+1], f); /* write green */
	  fputc(ptr[i+2], f); /* write blue */
	}
      }
    }
    else {
      /*ASCII*/
      int counter = 0;
      fprintf(f,"P3\n");
      fprintf(f,"# ascii ppm file created by osdemo.c\n");
      fprintf(f,"%i %i\n", width, height);
      fprintf(f,"255\n");
      for (y=height-1; y>=0; y--) {
	for (x=0; x<width; x++) {
	  i = (y*width + x) * 4;
	  fprintf(f, " %3d %3d %3d", ptr[i], ptr[i+1], ptr[i+2]);
	  counter++;
	  if (counter % 5 == 0)
	    fprintf(f, "\n");
	}
      }
    }
    fclose(f);
  }
}

bool OSMesaRender::init( int _width, int _height )
{
  buffer = NULL;
  ctx = OSMesaCreateContextExt( OSMESA_RGBA, 16, 0, 0, NULL );
  
  if (!ctx)
    {
      return false;
    }

  buffer = malloc( _width * _height * 4 * sizeof(GLubyte) );

  if (!buffer)
    {
      return false;
    }

  if (!OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, _width, _height))
    {
      return false;
    }

  width  = _width;
  height = _height;

  glDisable(GL_CULL_FACE);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);
  
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth(1);

  glShadeModel(GL_FLAT);

  glViewport(0, 0, _width, _height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(65.0, float(_width) / _height, 1.0, 1000.0);
  //gluPerspective(90, _width / _height, 0.1, 1000.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  return true;
}

void OSMesaRender::setCamera(const Turple3f &_eye, const Turple3f &_center, const Turple3f &_up)
{
  gluLookAt(_eye[0],
	    _eye[1],
	    _eye[2],
	    _center[0],
	    _center[1],
	    _center[2],
	    _up[0],
	    _up[1],
	    _up[2]);
}

void OSMesaRender::clear()
{
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}


void OSMesaRender::draw(Mesh2Ptr _mesh)
{
  //glBegin(GL_TRIANGLES);

  //glEnableClientState(GL_VERTEX_ARRAY);
  //glEnableClientState(GL_COLOR_ARRAY);
  
  //glVertexPointer(3, GL_FLOAT, sizeof(float) * 6, _mesh->data);
  //glEnableClientState(GL_VERTEX_ARRAY);
  //glColorPointer(3, GL_FLOAT, sizeof(float) * 6, &(_mesh->data[3]));

  
  //glDrawArrays(GL_TRIANGLES, 0, _mesh->size / 10);
  //glDrawArrays(GL_POINTS, 0, _mesh->size);
  //glDrawArrays(GL_TRIANGLES, 0, _mesh->size);
  //std::cout << "drawarray" << std::endl;
  
  glBegin(GL_TRIANGLES);

  for(int i = 0; i < _mesh->size; i+=3)
    {
      int j1, j2, j3;
      j1 = i * 6;
      j2 = (i + 1) * 6;
      j3 = (i + 2) * 6;
	
      glVertex3f( _mesh->data[j1 + 0], _mesh->data[j1 + 1], _mesh->data[j1 + 2] );
      glVertex3f( _mesh->data[j2 + 0], _mesh->data[j2 + 1], _mesh->data[j2 + 2] );
      glVertex3f( _mesh->data[j3 + 0], _mesh->data[j3 + 1], _mesh->data[j3 + 2] );
    }

  glEnd();
}

void OSMesaRender::draw(GLMeshPtr _mesh)
{
  glVertexPointer(3, GL_FLOAT, sizeof(GLfloat) * 6, _mesh->data1);
  glColorPointer(3, GL_FLOAT, sizeof(GLfloat) * 6, &(_mesh->data1[3]));

  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_COLOR_ARRAY);
  
  glDrawElements(GL_TRIANGLES, _mesh->index_size, GL_UNSIGNED_INT, _mesh->index);
    
}

void OSMesaRender::begin()
{
  clear();
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void OSMesaRender::end()
{
  glFlush();
}


void OSMesaRender::setMatrix(Turple3f &_loc, Turple2f &_ori)
{
  //glRotatef(_ori[0], 1, 0, 0);
  //glRotatef(_ori[1], 0, 1, 0);
  glTranslatef(_loc[0], _loc[1], _loc[2]);
}

void OSMesaRender::pushMatrix()
{
  glPushMatrix();
}

void OSMesaRender::popMatrix()
{
  glPopMatrix();
}
